import { reactive } from "vue";
import { v4 as uuidv4 } from "uuid";
import { tools } from "@/components/low-code/page-designer/utils/index"
import { LowCodeImp, LowCodeType, ComponentImp, CellImp, ModelImp, EventCenterImp, EventType, DataSourceType, DataSourceImp, GlobalConfig, SelectorImp } from './type'
import { Component } from './component'
import { EventCenter } from './eventCenter'
import { Model } from './model'
import { DataSource } from './dataSource'


class LowCode implements LowCodeImp {
    static custom: any;//自定义组件挂载点
    metaRefresh?: string;
    disabled?: boolean;
    currentKey!: string;
    domTree: { items: Array<ComponentImp> };    //组件树
    model!: any;                                //数据模型
    dataCenter!: { [key: string]: ComponentImp | CellImp };
    eventCollection!: Array<EventType>;        //事件集合
    dataSource!: Array<DataSourceType>;        //数据源集合
    globalConfig!: GlobalConfig;            //全局配置
    modelController!: ModelImp;//modelController 数据模型对象
    eventCenterController!: EventCenterImp//eventCenterController 事件控制对象
    dataSourceController!: DataSourceImp//DataSourceImp 数据源对象
    constructor({ domTree, model, eventCollection, dataSource, globalConfig }: LowCodeType) {
        this.domTree = domTree || {
            items: []
        }
        console.log('model', model)
        this.disabled = false;
        this.model = model || {
            form: {
                a: 1,
                b: 2,
                c: {
                    d: 3
                }
            }
        }
        this.dataCenter = {}
        this.eventCollection = eventCollection || [
            {
                code: '9303de27',
                type: 'custom',
                options: {},
                describe: '测试事件',
                func: ` const { data , $ , axios , ElMessage } = controller;`,
            },
        ]
        this.dataSource = dataSource || [
            {
                key: uuidv4(),
                name: "测试数据源",
                url: "",
                method: "GET",
                auto: false,
            }
        ]
        this.globalConfig = globalConfig || {
            labelWidth: 100,
            labelPosition: "left",
            size: "default"
        }
        this.init()
    }
    [x: string]: any;
    updateMetaRefresh() {
        this.metaRefresh = uuidv4()
    }
    init() {
        this.registrationControl()
        this.buildDomTree()
    }

    registrationControl() {
        this.modelController = new Model(this)  //数据模型初始化
        this.eventCenterController = new EventCenter(this)  //事件中心初始化
        this.dataSourceController = new DataSource(this)  //数据源初始化
    }
    buildDomTree() {
        let _this = this
        function copyComponent(com: Component): Component
        function copyComponent(com: CellImp): CellImp
        function copyComponent(com: Component | CellImp): Component | CellImp {
            let component;
            if ((<ComponentImp>com).group) {
                component = new Component(com, _this)
                _this.dataCenter[component.key] = component
            } else {
                com.key = tools.random()
                component = com
                _this.dataCenter[component.key] = component
            }
            if (component.items && component.items.length > 0) {
                component.items = component.items.map((item: Component | CellImp) => {
                    return copyComponent(item)
                })
            }
            return component
        }
        this.dataCenter = {}
        if (this.domTree && this.domTree.items && this.domTree.items.length > 0) {
            this.domTree.items = this.domTree.items.map(com => {
                return <Component>copyComponent(com)
            })
        }
        this.updateMetaRefresh()
    }
    removeComponent(key: string) {
        const component = this.dataCenter[key]
        if (component.items && component.items.length > 0) {
            component.items = component.items.map((item: Component | CellImp) => {
                return this.removeComponent(item.key)
            })
        }
        delete this.dataCenter[key]
    }
    addComponent(com: ComponentImp): ComponentImp
    addComponent(com: CellImp): CellImp
    addComponent(com: ComponentImp | CellImp): ComponentImp | CellImp {
        let component;
        if ((<ComponentImp>com).group) {
            component = <Component>(new Component(com, this))
        } else {
            component = com as CellImp
            component.key = tools.random()
        }
        this.dataCenter[component.key] = component
        if (component.items && component.items.length > 0) {
            component.items = component.items.map(item => {
                return this.addComponent(item)
            })
        }
        return component
    }
    copyComponent(com: ComponentImp, newkey: boolean): ComponentImp
    copyComponent(com: CellImp, newkey: boolean): CellImp
    copyComponent(com: ComponentImp | CellImp, newkey: boolean): ComponentImp | CellImp {
        let component: CellImp<any>;
        if ((<ComponentImp>com).group) {
            component = <Component>(new Component(com, this, newkey))
        } else {
            component = com as CellImp
            component.key = tools.random()
        }
        this.dataCenter[component.key] = component
        if (component.items && component.items.length > 0) {
            component.items = component.items.map((item: ComponentImp | CellImp) => {
                return this.copyComponent(item, newkey)
            })
        }
        return component
    }

    setcurrentKey(key: string) {
        this.currentKey = key
    }
}

const createLowCode = (arg: LowCodeType): LowCode => {
    return reactive(new LowCode({ ...arg }))
}

let lowCode = createLowCode({
    domTree: undefined
})

const updateLowCode = (arg?: LowCodeType): void => {
    const defaultMeta = {
        key: '',
        currentKey: '',
        domTree: {
            items: [],
        },
        model: {},
        dataCenter: {},
        eventCollection: [],
        dataSource: []
    }
    Object.assign(lowCode, defaultMeta, arg)
    lowCode.init()
}

export { LowCode, lowCode,  createLowCode,updateLowCode};
export type { ComponentImp, Component, CellImp, LowCodeImp, SelectorImp };